
//#undef UNICODE
//#undef _UNICODE
// cl Planecraft.cpp /utf-8 /EHsc /openmp /Ox

/*
0.1-alpha
0.2-beta
20240108
1.0(1) 飞机, Enemy0-2, bullet, meteorite
1.1(1) pause
1.1(2) fix.
1.2(3) remove console.
1.3(5) add Item, buff
2024-01-09
1.4(9) 加入袭击事件,陨石伤害改为tick*dmg
20240110
1.5(2) add carrier, debuff, carrier summon enemy
1.6 add Introduce
1.6.1 减慢Carrier的射击速度, 调整item概率和风暴变化速度
1.7 加入Medic, 治疗enemy
1.7.1 Medic由Carrier召唤
1.7.2 fix bug(Medic + Carrier hp)
20240111
1.7.3 提高Carrier的射击速度,HP,生命恢复速度,fix player.properties init err.
1.7.4 展示统计数据界面
1.7.5 降低大陨石下落速度, 提高Carrier射击速度(22->20->16)
20240112
1.7.6 Medic可正常生成, 增大Bomb爆炸范围(*100->*140)
1.7.7 fix bug:Medic渲染错误, Medic治疗行为由随机改为固定(.addon ctrl), 不移动的Medic能提供更高的生命恢复效果
20240123
1.7.8 修改游戏胜利的条件(消灭所有在场的敌人才可获胜),为所有敌方单位的生命恢复设置上限(21)
20240124
1.7.9 修复第二次开启游戏时bossbar显示(bug)
1.7.10 减少winrate后CRR召唤概率, 调整Item生成概率
1.7.11 fix(Item.per of normal entity.), /Ox
20240308
1.8 光影效果
1.8.1 启用OpenMP支持
20240309
1.8.2 优化光影(func'reset'), options
1.8.3 fix shadow restart'bullet's crash.
20240316-17
1.8.4 add option screen formally, add star
1.8.5 fix last, f3, display player fire effect
1.8.6 starmap, fix (short)stats.xxtime ++.
240816-17
1.9   fix short display, get_tps
1.9.1 add friend.
1.9.2 fix addon(unsigned), get debris.
1.9.3 friend.x eq to pl.x, fix friend.pos, render friend.
1.9.4 increase friend's hp, reduce dmg from pl, use debris to fix ship.
1.9.5 fix friend.multishot y-bul.
240819
1.9.6 fix friend multishot direct
*/

#include <omp.h>
#include <array>
#include <easyxgui.hpp>
#include "choice.h"
#pragma comment(lib, "choice.lib")
#define _ver1 L"1.9.6"
#define and &&
#define is ==
#define or ||
#define elif else if
//#include <seobjects.hpp>

typedef int tick_t;
typedef long ADDON;
constexpr int Width = 1660;
constexpr int Height= 930;
constexpr int EnemyMax = 16;
constexpr int BulletMax= 68+1;
constexpr int StoneMax = 8;
constexpr int ItemMax = 9;
constexpr int MagicMax = 6;
constexpr int PlaneWeight = 42;// length & width
constexpr int BulletWeight= 4;
constexpr int ItemWeight = 12;
constexpr int MagicWeight = 8;
constexpr int BulletSpeed = 8;// 8
constexpr int tps = 20;
constexpr int tpswait = 1000 / tps;
constexpr int PlayerSpeed = 10;
constexpr int EnemySpeed = 7;
constexpr int ItemSpeed = 7;
constexpr int MagicSpeed = 6;
constexpr int PlayerAtkCool = 4;
constexpr int EnemyAtkCool = 18;
constexpr int EnemyAttacksPer = 4; // 袭击概率, 出现大量敌对实体
constexpr int BossRateForWinner = 68; // bossrate up to this, 
constexpr int EnemyRegenerationMaxInOneTickTime = 21;
constexpr float CarrierHPMax = 24000;
constexpr int CarrierRegeneratePer = 40;
constexpr int CarrierAtkcoolMax = 16;
constexpr int CarrierTrySummonEnemyPer = 5;
constexpr int StarMax = 520;
constexpr bool CanMeteoriteDestroyBullet = true;
constexpr float BulletDamageMain = 200;
constexpr float MeteoriteDamageBase = 20; // this * radius = damae
constexpr float EnemyBombBlastRange = (float)PlaneWeight * 2 + 140;
constexpr float EnemyBombBlastDamageBase = 160*3.2; // this + Euladis * 2 # this = dmg

constexpr int FriendMax = 3;
constexpr int FriendCooldn = 5000; //ms
constexpr float FriendHpMax = 8000;
constexpr float PlayerShieldHpMax = 1000.0;
constexpr int EnemyNotEscapeProb = 70 - 2 + 1;

constexpr tick_t get_tps(const int ms, const tick_t tps_ = tps)
{
    return ms / tpswait;
}

enum Direct {
    D_LEFT, D_RIGHT, D_DOWN
};
enum Enemy_Type {
    ET_NORMAL, ET_BOSS, ET_BOMB, ET_MEDIC, ET_CARRIER
};
enum Entitybullet_Belong {
    EB_PLAYER, EB_ENEMY
};
enum Move_Method {
    MM_XLINE, MM_YLINE, MM_FLOAT
};
enum Item_Type {
    IT_POWER, IT_AID, IT_SHIELD
};
enum MagicBullet_Type {
    MT_FIRE, MT_BLIND
};
int ItemSelectWeight[3] = {20, 32, 12};
int MagicSelectWeight[2] = {11, 27};
constexpr tick_t PowerTickMax = 20 * 8;
constexpr tick_t AidTickMax = 20 * 18;
constexpr tick_t FireTickMax = 20 * 5; // hp-4, shield-1
constexpr tick_t BlindTickMax = 20 * 4;
constexpr float ShieldReduceDamagePer = 0.95; // dmg = dmg * (1 - this * (1000.0f-ShieldHP))
constexpr int8_t GetItemPer = 80; // item爆率

typedef int8_t DIRECT;

typedef struct __Plane__
{
    int x;
    int y;
    float hp;
    COLORREF color;
}__Plane;

typedef struct __Player
{
    __Plane base;
    int8_t atkcool;
    float ShieldHP;
    tick_t Aid;
    tick_t Multishot;
    tick_t Fire; // debuff
    tick_t Blind; // debuff
    /* call */
    tick_t friend_tick;
    int plane_debris;
}Player;

#define __DECLNPC(_npcname_s) \
typedef struct _npcname_s\
{\
    __Plane base;\
    bool liv;\
    DIRECT d;\
    int8_t dtype;\
    int8_t atkcool;\
    ADDON addon;\
    int8_t regen_thistick;\
}_npcname_s;

__DECLNPC(Enemy);
__DECLNPC(Friend);

typedef struct __Bullet
{
    int x;
    int y;
    float damage;
    int dx;
    int dy;
    bool liv;
    int8_t belong;
    COLORREF col;
}Bullet;

typedef struct
{
    int x;
    int y;
    float radius;
    bool liv;
    int8_t movem;
    int_fast8_t yspeed; // 4 ~ 10
    int8_t xspeed; // MM_FLOAT only
}Meteorite;

typedef struct __Item
{
    int x;
    int y;
    //int speed; == enemyspeed
    int8_t dtype;
    bool liv;
}Item;

typedef struct
{
    int x;
    int y;
    COLORREF col;
    int8_t dtype;
    bool liv;
}Magic;


struct
{
    long Shoot;
    long onTarget;
    int q;
    double behit;
    long score;
    short PlayTimes;
    long double hit;
    long double ShieldAbsorb;
    
    int q_normal;
    int q_boss;
    int q_bomb;
    int q_carrier;
    int q_medic;
    short passTimes;
    short losetimes;
    
}StatisticalData{
    0, 0, 0, 0.0, 0, 0, 0.0, 0.0,
    0, 0, 0, 0, 0, 0, 0
};

struct Shadow_Options
{
    // use?
    bool use;
    // light?
    int bullet;
    int spacecraft;
    bool star;
}shadow_option{
    true, 48, 0, false
};

struct MyColor
{
    uint8_t r;
    uint8_t g;
    uint8_t b;
    //uint8_t a;
};

inline uint8_t reduce(uint8_t value, uint8_t m)
{
    if (value < m) {
        return 0;
    } else {
        return value - m;
    }
}
inline void increase255(uint8_t& value, uint8_t inc)
{
    //uint8_t v = value;
    int i = value + inc;
    if (i > 255) {
        value = 255;
    } else {
        value = static_cast<uint8_t>(i);
    }
}

class _Shadow {
    public:
        MyColor lightmap[Height][Width];
        IMAGE bg;
        void light(int x, int y, int l = 120, int dec = 1);
        void blit_light();
        void bl(int);
        void reset(){
            #pragma omp parallel for num_threads(4)
            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    this->lightmap[i][j].r = 4;
                    this->lightmap[i][j].g = 6;
                    this->lightmap[i][j].b = 16;
                }
            }
            
            //memset(this->lightmap, 0, sizeof(this->lightmap));
        }
}Shadow;

class Options__ {
    public:
        bool display_star;
        bool random_star_color;
        bool twinkling_stars;
        int star_density;
        void init(){
            this->display_star = true;
            this->random_star_color = true;
            this->twinkling_stars = true;
            this->star_density = 300;
        }
        void _main();
    protected:
        void shader();
        void _display();
    private:
        static int _main_h(EasyCtrl *, ExMessage *, int *);
        static int _display_h(EasyCtrl *, ExMessage * , int*);
}options;

inline COLORREF randcolor_lighter()
{
    int _Max = RandInt(256, 720);
    int r = RandInt(0, _Max);
    if (r>255) {r=255;}
    _Max -= r;
    if (_Max <= 0) {
        return RGB(r, 0, 0);
    }
    int g = RandInt(0, _Max);
    if (g > 255) {g = 255;}
    _Max -= g;
    if (_Max <= 0) {
        return RGB(r, g, 0);
    }
    if (_Max > 255) {_Max = 255;} elif (_Max < 0) {_Max = 0;}
    return RGB(r, g, _Max);
}

class Stars_ {
    public:
        int x;
        int y;
        COLORREF col;
        long long display;
        bool displaying;
        tick_t xmovtick;
        bool big ;
        void init() {
            this->x = RandomDistInt(1, Width-12);
            this->y = RandomDistInt(0, Height - 16);
            this->col = options.random_star_color? randcolor_lighter(): RandomColor(210, 254);
            this->display = seg::Times::get_ticks();
            this->displaying = true;
            this->xmovtick = 0;
            this->big = false;
        }
        void mov_and_render();
};

wchar_t ss[280];

Player pl;
Enemy EnemyList[EnemyMax];
Bullet BulletList[BulletMax];
Meteorite StoneList[StoneMax];
Item ItemList[ItemMax];
Magic MagicList[MagicMax];
std::array<Stars_, StarMax> StarList;
Friend FriendList[3];

// runtime
int EnemyTypeWeight[4] = {10, 1, 1, 1};
int windy = 1; // wind move stone
int score = 0;
Enemy *CarrierBossBarMain = nullptr;
int Enemy_Count = 0;
int Stone_Count = 0;
int BulletCount = 0;
int Items_Count = 0;
int Magic_Count = 0;
int Star_Count  = 0;

void initplayer();
void initenemies();
void initbullets();
void initstones();
void inititems();
void initmagics();
void initstars();
void initfriends();

void CreateMeteorite();
void SummonEnemy();
void SummonFriend(Player &self, int8_t _type_f);
void CreateBullet(Player &self);
void CreateBullet(Enemy & self);
void CreateItem(Enemy &self); // 爆金币
void CreateMagic(Enemy &self);
void CreateBullet(Friend &self);
void SummonCarrier();

void mov(Player &self);
void mov(Enemy &self);
void mov(Bullet &self);
void mov(Meteorite &self);
void mov(Item &self);
void mov(Magic &self);
void mov(Friend &self);
void display_stars();

void shoot(Player &self);
void shoot(Enemy &self);
void hit(Player &self, float dmg0);
void hit(Enemy &self, float dmg, int8_t by);
void hit(Friend &self, float dmg, int8_t by);

void fire(Player &self);

void render(Player &self);
void render(Enemy &self);
void render(Friend &self);
void render(Bullet &self);
void render(Meteorite &self);
void render(Item &self);
void render(Magic &self);

void draw_bar(Enemy *carrier);

void Introduce();
void ShowStatistics();
/*
bool errflg = false;
void printm(const wchar_t *s)
{
    time_t Now;
    time(&Now);
    tm *p = localtime(&Now);
    wprintf(L"[%2d:%2d:%2d] %s\n", p->tm_hour, p->tm_min, p->tm_sec, s);
}
HANDLE stdouthdl;
void cerr(const wchar_t *s, WORD col = FOREGROUND_INTENSITY | FOREGROUND_RED)
{
    SetConsoleTextAttribute(stdouthdl, col);
    printm(s);
    SetConsoleTextAttribute(stdouthdl,FOREGROUND_INTENSITY|FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED);
}
*/
// eular distance(line)
float EulaDis(int x1, int y1,   int x2, int y2)
{
    long f = (x1 - x2) * (x1 - x2)  +  (y1 - y2) * (y1 - y2);
    return sqrtf(f);
}
bool prob(int p)
{
    return p > seg::Math::randint(0, 100);
}

void StartNormal()
{
    initplayer(); initenemies(); initbullets(); initstones(); inititems(); initmagics(); initstars(); initfriends();
    EnemyTypeWeight[0] = 30; // normal
    EnemyTypeWeight[1] = 4;  // boss
    EnemyTypeWeight[2] = 10; // bomb
    EnemyTypeWeight[3] = 2;  // Medic
    Enemy_Count = 0;
    Stone_Count = 0;
    BulletCount = 0;
    Items_Count = 0;
    score = 0;
    settextcolor(RGB(255, 160, 255));
    StatisticalData.PlayTimes++;
    if (prob(48))
    {
        windy = seg::Math::randint(1, 3);
    }
    else if (prob(92))
    {
        windy = -seg::Math::randint(1, 3);
    } else {
        windy = 0;
    }
    bool pressingf3 = false;
    bool showf3text = true;
    bool SummonCarrier_1 = true;
    CarrierBossBarMain = nullptr;
    constexpr int AddCarrierTime_1 = (float)BossRateForWinner * 0.72;
    seg::Times::Clock FPS;
    FPS.init();
    FPS.tick(6000);
    auto addTime = seg::Times::get_ticks(); // + 
    auto EntityTps = addTime;
    auto TickNow = EntityTps;
    auto AddEnemyTime = TickNow;
    auto AdjustETW = TickNow;
    auto Bullet_Tps = TickNow;
    while (true)
    {
        FPS.tick();
        if (shadow_option.use) {
            Shadow.reset();
        }
        TickNow = seg::Times::get_ticks();
        if (TickNow >= addTime)
        {
            addTime = TickNow + seg::Math::randint(1600, 12600);
            CreateMeteorite();
            if (prob(18))
            {
                if (prob(48))
                {
                    windy = seg::Math::randint(1, 3);
                }
                else if (prob(92))
                {
                    windy = -seg::Math::randint(1, 3);
                } else {
                    windy = 0;
                }
            }
        }
        if (TickNow >= AddEnemyTime and (EnemyTypeWeight[1] <= BossRateForWinner))
        {
            AddEnemyTime = TickNow + seg::Math::randint(1630, 5260);
            SummonEnemy();
            if (Enemy_Count <= 0)
            {
                SummonEnemy();
            }
            if (SummonCarrier_1 and EnemyTypeWeight[1] is AddCarrierTime_1)
            {
                SummonCarrier_1 = false;
                SummonCarrier();
            }
        }
        if (TickNow >= AdjustETW)
        {
            AdjustETW = TickNow + 20'000;
            EnemyTypeWeight[1] ++;
        }
        if (TickNow >= EntityTps)
        {
            EntityTps = TickNow + tpswait;
            if (prob(30))
            {
                pl.base.hp += 1;
                if (pl.base.hp > 1000)
                {
                    pl.base.hp = 1000.0f;
                }
            }
            mov(pl);
            for (int i = 0; i < EnemyMax; i++)
            {
                if (EnemyList[i].liv)
                {
                    mov(EnemyList[i]);
                }
            }
            for (int i = 0; i < FriendMax; i++)
            {
                if (FriendList[i].liv)
                {
                    mov(FriendList[i]);
                }
            }
            for (int i = 0; i < StoneMax; i++)
            {
                if (StoneList[i].liv)
                {
                    mov(StoneList[i]);
                }
            }
            for (int i = 0; i < ItemMax; i++)
            {
                if (ItemList[i].liv)
                {
                    mov(ItemList[i]);
                }
            }
            for (int i = 0; i < MagicMax; ++i)
            {
                if (MagicList[i].liv)
                {
                    mov(MagicList[i]);
                }
            }
        }
        if (TickNow >= Bullet_Tps)
        {
            Bullet_Tps = TickNow + 10;
            #pragma omp parallel for num_threads(2)
            for (int i = 0; i < BulletMax; i++)
            {
                if (BulletList[i].liv)
                {
                    mov(BulletList[i]);
                }
            }
        }
        // render
        if (pl.Blind <= 0)
        {
            if (shadow_option.use) {
                Shadow.blit_light();
            } else {
                seg::render::fill(RGB(4, 6, 16));
            }
            if (options.display_star){
                #pragma omp parallel for num_threads(4)
                for (int i = 0; i < StarList.size(); i++) {
                    StarList.at(i).mov_and_render();
                }
            }
            for (int i = 0; i < StoneMax; i++)
            {
                if (StoneList[i].liv)
                {
                    render(StoneList[i]);
                }
            }
            for (int i = 0; i < EnemyMax; i++)
            {
                if (EnemyList[i].liv)
                {
                    render(EnemyList[i]);
                }
            }
            for (int i = 0; i < FriendMax; i++)
            {
                if (FriendList[i].liv)
                {
                    render(FriendList[i]);
                }
            }
            for (int i = 0; i < ItemMax; i++)
            {
                if (ItemList[i].liv)
                {
                    render(ItemList[i]);
                }
            }
        }
        else
        {
            seg::render::fill(RGB(255, 255, 255));
        }
        for (int i = 0; i < BulletMax; i++)
        {
            if (BulletList[i].liv)
            {
                render(BulletList[i]);
            }
        }
        for (int i = 0; i < MagicMax; i++)
        {
            if (MagicList[i].liv)
            {
                render(MagicList[i]);
            }
        }
        render(pl);
        draw_bar(CarrierBossBarMain);
        if (showf3text){
            swprintf(ss, L"FPS:%d/%d Windy:%d BR: %d/%d", FPS.get_fps(), FPS.ask_fpsmin(), windy, EnemyTypeWeight[1], BossRateForWinner);// boss rate
            outtextxy(0, 0, (LPCTSTR)(ss));
            swprintf(ss, L"E:%d, B:%d, S:%d, I:%d, M:%d", Enemy_Count, BulletCount, Stone_Count, Items_Count, Magic_Count);
            outtextxy(0, 16, (LPCTSTR)ss);
            // right top
            swprintf(ss, L"Position: (%d, %d), Score:%d", pl.base.x, pl.base.y, score);
            seg::render::text(Width-1, 0, ss, seg::render::Place::righttop);
            swprintf(ss, L"HP:%.2f, Power:%d, Aid:%d, Shield:%.1f", pl.base.hp, pl.Multishot,pl.Aid,pl.ShieldHP);
            seg::render::text(Width-1, 16, ss, seg::render::Place::righttop);
            swprintf(ss, L"Fire:%d, Blind:%d", pl.Fire, pl.Blind);
            seg::render::text(Width-1, 32, ss, seg::render::Place::righttop);
        }
        seg::render::flip();
        if (pl.base.hp <= 0)
        {
            //printm(L"Player lose.");
            //Sleep(3000);
            while (true)
            {
                Sleep(50);
                swprintf(ss, L"You lose. Score is: %d", score);
                StatisticalData.losetimes ++;
                seg::render::text(Width/2, Height/2-10, ss, seg::render::Place::center);
                swprintf(ss, L"Press ENTER to quit.");
                seg::render::text(Width/2, Height/2+10, ss, seg::render::Place::center);
                seg::render::flip();
                if (seg::Key::GetVirtualKey(VK_RETURN))
                {
                    break;
                }
            }
            StatisticalData.score += score;
            return;
        }
        if (EnemyTypeWeight[1] > BossRateForWinner /*and CarrierBossBarMain != nullptr*/) {
            if //(CarrierBossBarMain->liv is false)
            (Enemy_Count <= 0)
            {
                //printm(L"Player win!");
                while (true)
                {
                    Sleep(50);
                    swprintf(ss, L"You win! Score is: %d", score);
                    StatisticalData.passTimes ++;
                    seg::render::text(Width/2, Height/2-10, ss, seg::render::Place::center);
                    swprintf(ss, L"Press ENTER to quit.");
                    seg::render::text(Width/2, Height/2+10, ss, seg::render::Place::center);
                    seg::render::flip();
                    if (seg::Key::GetVirtualKey(VK_RETURN))
                    {
                        break;
                    }
                }
                StatisticalData.score += score;
                return;
            }
        }
        if (seg::Key::GetVirtualKey('P'))
        {
            while (true)
            {
                swprintf(ss, L"已暂停, 按Enter继续, ESC退出");
                seg::render::text(Width/2, Height /2, (TCHAR*)ss, seg::render::Place::center);
                seg::render::flip();
                Sleep(50);
                if (seg::Key::GetVirtualKey(VK_RETURN))
                {
                    break;
                } elif (seg::Key::GetVirtualKey(VK_ESCAPE)) {
                    StatisticalData.score += score;
                    return;
                }
            }
        }
        if (seg::Key::GetVirtualKey(VK_F3)) {
            if (pressingf3) {
                pass
            } else {
                showf3text = !showf3text;
            }
        } else {
            pressingf3 = false;
        }
    }
}

//int __stdcall wWinMain(HINSTANCE__ *hInstance, HINSTANCE__ *hPrevInstance, LPWSTR lpCmdLine, int nshow)
//{
//    seg::EasyX_Initialize()
//}

//int wmain(int argc, wchar_t *argv)
int __stdcall wWinMain(HINSTANCE__ *hInstance, HINSTANCE__ *hPrevInstance, LPWSTR lpCmdLine, int nshow)
{
    //printm(L"Initialize Planecraft " _ver1);
    seg::EasyX_Initialize(Width, Height, L"Planecraft " _ver1 );//EX_SHOWCONSOLE);
    SetWindowPos(seg::MainHandle, NULL, 10, 10, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
    seg::render::fill(RGB(30, 50, 68+1));
    settextcolor(RGB(255, 196, 20));
    seg::render::text(Width/2, Height/2, L"Press 'S' to start.", seg::render::Place::center);
    //stdouthdl = GetStdHandle(STD_OUTPUT_HANDLE);
    seg::render::flip();
    Shadow.bg.Resize(Width, Height);
    const int OpenMP_ThreadNum = omp_get_num_threads();
    const int OpenMP_ProcNum   = omp_get_num_procs();
    wchar_t somp[100];
    swprintf(somp, L"OpenMP 2.0. Core:%d/%d", OpenMP_ThreadNum, OpenMP_ProcNum);
    options.init();
    //printm(L"Enter mainloop.");
    while (true)
    {
        Sleep(100);
        seg::render::fill(RGB(30, 50, 68+1));
        seg::render::text(Width/2, Height/2-10, L"Press 'S' to start, 'I' for help, 'O' for option.", seg::render::Place::center);
        //swprintf(
        //    ss, L"Shoot: %ld,  On Target: %ld,  Q: %d,  Score: %ld,  Behit: %.3lf",
        //    StatisticalData.Shoot,StatisticalData.onTarget,
        //    StatisticalData.q, StatisticalData.score, StatisticalData.behit
        //);
        seg::render::text(Width/2, Height/2+10, L"Type 'T' to view statistical data", seg::render::Place::center);
        outtextxy(0, Height - 20, somp);
        seg::render::flip();
        if (seg::Key::GetVirtualKey('S'))
        {
            StartNormal();
        }
        elif (seg::Key::GetVirtualKey('I'))
        {
            Introduce();
        }
        elif (seg::Key::GetVirtualKey('T'))
        {
            ShowStatistics();
        }
        elif (seg::Key::GetVirtualKey('O')) {
            options._main();
        }
    }
}


void initplayer()
{
    pl.base.hp = 1000.0;
    pl.base.x = Width/2;
    pl.base.y = Height - PlaneWeight - 1;
    pl.base.color = RGB(0, 255, 255);
    pl.atkcool = 0;
    pl.Aid = 0;
    pl.Blind = 0;
    pl.Fire = 0;
    pl.Multishot = 0;
    pl.ShieldHP = 0;
    pl.friend_tick = 0;
    pl.plane_debris = 0;
}

void initenemies()
{
    for (int i = 0; i < EnemyMax; i++)
    {
        EnemyList[i].liv = false;
    }
    Enemy_Count = 0;
}
void initfriends()
{
    for (int i = 0; i < FriendMax; i++)
    {
        FriendList[i].liv = false;
    }
}

void initbullets()
{
    for (int i = 0; i < BulletMax; i++)
    {
        BulletList[i].liv = false;
    }
    BulletCount = 0;
}

void initstones()
{
    for (int i = 0; i < StoneMax; i++)
    {
        StoneList[i].liv = false;
    }
    Stone_Count = 0;
}

void inititems()
{
    for (int i = 0; i < ItemMax; i++)
    {
        ItemList[i].liv = false;
    }
    Items_Count = 0;
}

void initmagics()
{
    for (int i = 0; i < MagicMax; i++)
    {
        MagicList[i].liv = false;
    }
    Magic_Count = 0;
}

void initstars()
{
    for (int i = 0; i < StarList.size(); i++) {
        StarList.at(i).init();
    }
}
void display_stars()
{
    for (int i = 0; i < StarList.size(); i++)
    {
        StarList.at(i).mov_and_render();
    }
}

void __CreateStone()
{
    for (int i = 0; i < StoneMax; i++)
    {
        if (StoneList[i].liv == false)
        {
            StoneList[i].liv = true;
            StoneList[i].x = seg::Math::randint(100, Width-100);
            StoneList[i].y = 100;
            if (prob(50))
            {
                StoneList[i].movem = MM_YLINE;
                StoneList[i].radius = seg::Math::randint(28, 180);
                StoneList[i].yspeed = seg::Math::randint(1, 8);
            }
            else
            {
                StoneList[i].movem = MM_FLOAT;
                StoneList[i].radius = seg::Math::randint(18, 56);
                StoneList[i].yspeed = seg::Math::randint(6, 12);
                if (prob(50))
                {
                    StoneList[i].xspeed = seg::Math::randint(0, 8);
                } else {
                    StoneList[i].xspeed = -seg::Math::randint(0, 7);
                }
            }
            Stone_Count ++;
            return;
        }
    }
    
}
void CreateMeteorite()
{
    int i = seg::Math::randint(0, 4);
    if (i == 0) {return;}
    for (int j = 0; j < i; j++)
    {
        __CreateStone();
    }
}

void __SummonEnemy()
{
    static int _[3] = {10, 10, 4};
    for (int i = 0; i < EnemyMax; i++)
    {
        if (EnemyList[i].liv == false)
        {
            EnemyList[i].liv = true;
            EnemyList[i].d = WeightChoice(_, 3);
            EnemyList[i].dtype = WeightChoice(EnemyTypeWeight, 4);
            EnemyList[i].base.y = PlaneWeight+1;
            EnemyList[i].base.x = seg::Math::randint(PlaneWeight, Width - PlaneWeight);
            EnemyList[i].base.hp= 1000;
            EnemyList[i].regen_thistick = 0;
            switch (EnemyList[i].dtype)
            {
            case ET_NORMAL:
            {
                EnemyList[i].base.color = RGB(255, 255, 8);
            }
                break;
            case ET_BOSS:
            {
                EnemyList[i].base.color = RGB(0xb3, 0x0e, 0xdc);
            } break;
            
            case ET_BOMB:
            {
                EnemyList[i].base.color = RGB(255, 32, 0);
                EnemyList[i].addon = -10;
            } break;
            
            case ET_MEDIC:
            {
                EnemyList[i].base.color = RGB(0, 255, 132);
                if (EnemyList[i].d is D_DOWN)
                {
                    // stand, and higher health
                    EnemyList[i].addon = 16;
                } else {
                    EnemyList[i].addon = 6;
                }
            } break;
            
            default:
                //errflg = true;
                //cerr(L"Error in summon enemy: Unknown dtype.");
                EnemyList[i].base.color = RGB(255, 255, 255);
                break;
            }
            Enemy_Count++;
            return;
            break;
        }
    }
    
}
void SummonEnemy()
{
    if (prob(EnemyAttacksPer))
    {
        int i = seg::Math::randint(4, 9);
        for (int j = 0; j < i; j++)
        {
            __SummonEnemy();
        }
    }
    else
    {
        int i = seg::Math::randint(0, 2);
        if (i == 0) {return;}
        for (int j = 0; j < i; j++)
        {
            __SummonEnemy();
        }
    }
}

void SummonFriend(Player &self, int8_t _type_f)
{
    for(int i = 0; i < FriendMax; i++)
    {
        if(FriendList[i].liv == false)
        {
            
            switch (_type_f)
            {
            case 2: {
                if (self.plane_debris < 120) {
                    break;
                }
                FriendList[i].liv = true;
                FriendList[i].d = 2;
                FriendList[i].dtype = _type_f;
                FriendList[i].base.y = self.base.y - PlaneWeight * 2 - 2;
                FriendList[i].base.x = self.base.x;
                FriendList[i].base.hp= FriendHpMax;
                FriendList[i].regen_thistick = 0;
                FriendList[i].base.color = RGB(50, 186, 192);
                FriendList[i].addon = 1;
                FriendList[i].atkcool = 0;
                
                self.friend_tick = (tick_t)get_tps(FriendCooldn);
                self.plane_debris -= 120;
            }
                break;
            
            case 1:
            default:
                if (self.plane_debris < 50) {
                    break;
                }
                FriendList[i].liv = true;
                FriendList[i].d = prob(50) ? 1 : 0;
                FriendList[i].dtype = 1;
                FriendList[i].base.y = self.base.y - PlaneWeight * 2 - 6;
                FriendList[i].base.x = self.base.x;
                FriendList[i].base.hp= FriendHpMax;
                FriendList[i].regen_thistick = 0;
                FriendList[i].base.color = RGB(50, 186, 192);
                FriendList[i].addon = 0;
                
                self.friend_tick = (tick_t)get_tps(FriendCooldn);
                self.plane_debris -= 35;
                break;
            }
        }
    }
}

void __Player_Multishot(Player &self)
{
    int i;
    for (i = 0; i < BulletMax; i++)
    {
        if (BulletList[i].liv == false)
        {
            BulletList[i].liv = true;
            BulletList[i].x = self.base.x;
            BulletList[i].y = self.base.y - PlaneWeight - 5;
            BulletList[i].damage = BulletDamageMain / 2;
            BulletList[i].belong = EB_PLAYER;
            BulletList[i].dx = BulletSpeed / 3;
            BulletList[i].dy = -BulletSpeed;
            BulletList[i].col = RGB(0xc5, 0xfb, 0x46) ;
            BulletCount++;
            break;
        }
    }
    for (i ; i < BulletMax; i++)
    {
        if (BulletList[i].liv == false)
        {
            BulletList[i].liv = true;
            BulletList[i].x = self.base.x;
            BulletList[i].y = self.base.y - PlaneWeight - 5;
            BulletList[i].damage = BulletDamageMain / 3;
            BulletList[i].belong = EB_PLAYER;
            BulletList[i].dx = BulletSpeed / 2;
            BulletList[i].dy = -BulletSpeed;
            BulletList[i].col = RGB(0xc5, 0xfb, 0x46) ;
            BulletCount++;
            break;
        }
    }
    for (i ; i < BulletMax; i++)
    {
        if (BulletList[i].liv == false)
        {
            BulletList[i].liv = true;
            BulletList[i].x = self.base.x;
            BulletList[i].y = self.base.y - PlaneWeight - 5;
            BulletList[i].damage = BulletDamageMain / 2;
            BulletList[i].belong = EB_PLAYER;
            BulletList[i].dx = -(BulletSpeed / 3);
            BulletList[i].dy = -BulletSpeed;
            BulletList[i].col = RGB(0xc5, 0xfb, 0x46) ;
            BulletCount++;
            break;
        }
    }
    for (i ; i < BulletMax; i++)
    {
        if (BulletList[i].liv == false)
        {
            BulletList[i].liv = true;
            BulletList[i].x = self.base.x;
            BulletList[i].y = self.base.y - PlaneWeight - 5;
            BulletList[i].damage = BulletDamageMain / 3;
            BulletList[i].belong = EB_PLAYER;
            BulletList[i].dx = -(BulletSpeed / 2);
            BulletList[i].dy = -BulletSpeed;
            BulletList[i].col = RGB(0xc5, 0xfb, 0x46) ;
            BulletCount++;
            break;
        }
    }
}
void CreateBullet(Player &self)
{
    for (int i = 0; i < BulletMax; i++)
    {
        if (BulletList[i].liv == false)
        {
            BulletList[i].liv = true;
            BulletList[i].x = self.base.x;
            BulletList[i].y = self.base.y - PlaneWeight;
            BulletList[i].damage = BulletDamageMain;
            BulletList[i].belong = EB_PLAYER;
            BulletList[i].dx = 0;
            BulletList[i].dy = -BulletSpeed;
            BulletList[i].col = RGB(255, 0, 255) ;
            BulletCount ++;
            break;
        }
    }
    if (self.Multishot > 0)
    {
        __Player_Multishot(self);
    }
}
void CreateBullet(Friend &self)
{
    switch (self.dtype)
    {
    case 2:{
        for (int i = 0; i < BulletMax; i++)
        {
            if (BulletList[i].liv == false)
            {
                BulletList[i].liv = true;
                BulletList[i].x = self.base.x;
                BulletList[i].y = self.base.y - PlaneWeight - 1 - EnemySpeed * 0.9;
                BulletList[i].damage = BulletDamageMain;
                BulletList[i].belong = EB_PLAYER;
                BulletList[i].dx = 0;
                BulletList[i].dy = -BulletSpeed;
                BulletList[i].col = RGB(255, 0, 255) ;
                BulletCount ++;
                break;
            }
        }
        
        
        /* Multishot */
        {
            int i;
            for (i = 0; i < BulletMax; i++)
            {
                if (BulletList[i].liv == false)
                {
                    BulletList[i].liv = true;
                    BulletList[i].x = self.base.x;
                    BulletList[i].y = self.base.y - PlaneWeight - 2 - EnemySpeed * 0.9;
                    BulletList[i].damage = BulletDamageMain / 4;
                    BulletList[i].belong = EB_PLAYER;
                    BulletList[i].dx = self.addon;
                    BulletList[i].dy = -BulletSpeed;
                    BulletList[i].col = RGB(0xc5, 0xfb, 0x46) ;
                    BulletCount++;
                    break;
                }
            }
            for (i ; i < BulletMax; i++)
            {
                if (BulletList[i].liv == false)
                {
                    BulletList[i].liv = true;
                    BulletList[i].x = self.base.x;
                    BulletList[i].y = self.base.y - PlaneWeight - 5 + 3 - EnemySpeed * 0.9;
                    BulletList[i].damage = BulletDamageMain / 4;
                    BulletList[i].belong = EB_PLAYER;
                    BulletList[i].dx = -self.addon;
                    BulletList[i].dy = -BulletSpeed;
                    BulletList[i].col = RGB(0xc5, 0xfb, 0x46) ;
                    BulletCount++;
                    break;
                }
            }
            self.addon += 1;
            if (self.addon > (BulletSpeed * 2) /* ||  self.addon <= 0 */) {
                self.addon = /*1*/-BulletSpeed * 2 - 1;
            } elif (self.addon < 0) {
                pass; // back, <- lI|Il ->
            } else {
                pass;
            }
        }
    }
        break;
    
    case 1:
    default:
    {
        for (int i = 0; i < BulletMax; i++)
        {
            if (BulletList[i].liv == false)
            {
                BulletList[i].liv = true;
                BulletList[i].x = self.base.x;
                BulletList[i].y = self.base.y - PlaneWeight;
                BulletList[i].damage = BulletDamageMain;
                BulletList[i].belong = EB_PLAYER;
                BulletList[i].dx = 0;
                BulletList[i].dy = -BulletSpeed;
                BulletList[i].col = RGB(255, 0, 255) ;
                BulletCount ++;
                break;
            }
        }
    }
        break;
    }
}

// main
void __CreateBullet1(Enemy &self)
{
    for (int i = 0; i < BulletMax; i++)
    {
        if (BulletList[i].liv == false)
        {
            BulletList[i].liv = true;
            BulletList[i].x = self.base.x;
            BulletList[i].y = self.base.y + PlaneWeight + 5;
            BulletList[i].damage = BulletDamageMain;
            BulletList[i].belong = EB_ENEMY;
            BulletList[i].dx = 0;
            BulletList[i].dy = BulletSpeed;
            BulletList[i].col = RGB(255, 0, 255) ;
            BulletCount++;
            break;
        }
    }
}
// added
void __CreateBullet2(Enemy &self)
{
    int i;
    for (i = 0; i < BulletMax; i++)
    {
        if (BulletList[i].liv == false)
        {
            BulletList[i].liv = true;
            BulletList[i].x = self.base.x;
            BulletList[i].y = self.base.y + PlaneWeight + 5;
            BulletList[i].damage = BulletDamageMain / 6;
            BulletList[i].belong = EB_ENEMY;
            BulletList[i].dx = BulletSpeed / 3;
            BulletList[i].dy = BulletSpeed;
            BulletList[i].col = RGB(0xc5, 0xfb, 0x46) ;
            BulletCount++;
            break;
        }
    }
    for (i ; i < BulletMax; i++)
    {
        if (BulletList[i].liv == false)
        {
            BulletList[i].liv = true;
            BulletList[i].x = self.base.x;
            BulletList[i].y = self.base.y + PlaneWeight + 5;
            BulletList[i].damage = BulletDamageMain / 8;
            BulletList[i].belong = EB_ENEMY;
            BulletList[i].dx = BulletSpeed / 2;
            BulletList[i].dy = BulletSpeed;
            BulletList[i].col = RGB(0xc5, 0xfb, 0x66) ;
            BulletCount++;
            break;
        }
    }
    for (i ; i < BulletMax; i++)
    {
        if (BulletList[i].liv == false)
        {
            BulletList[i].liv = true;
            BulletList[i].x = self.base.x;
            BulletList[i].y = self.base.y + PlaneWeight + 5;
            BulletList[i].damage = BulletDamageMain / 6;
            BulletList[i].belong = EB_ENEMY;
            BulletList[i].dx = -(BulletSpeed / 3);
            BulletList[i].dy = BulletSpeed;
            BulletList[i].col = RGB(0xc5, 0xfb, 0x46) ;
            BulletCount++;
            break;
        }
    }
    for (i ; i < BulletMax; i++)
    {
        if (BulletList[i].liv == false)
        {
            BulletList[i].liv = true;
            BulletList[i].x = self.base.x;
            BulletList[i].y = self.base.y + PlaneWeight + 5;
            BulletList[i].damage = BulletDamageMain / 8;
            BulletList[i].belong = EB_ENEMY;
            BulletList[i].dx = -(BulletSpeed / 2);
            BulletList[i].dy = BulletSpeed;
            BulletList[i].col = RGB(0xc5, 0xfb, 0x66) ;
            BulletCount++;
            break;
        }
    }
}
void CreateBullet(Enemy &self)
{
    switch (self.dtype)
    {
    case ET_NORMAL:
    {
        __CreateBullet1(self);
    }
        break;
    
    case ET_BOSS:
    {
        __CreateBullet1(self);
        __CreateBullet2(self);
    } break;
    
    default:
        break;
    }
}

void CreateItem(Enemy &self)
{
    for (int i = 0; i < ItemMax; i++)
    {
        if (ItemList[i].liv is false)
        {
            ItemList[i].liv = true;
            ItemList[i].x = self.base.x;
            ItemList[i].y = self.base.y;
            ItemList[i].dtype = WeightChoice(ItemSelectWeight, 3);
            Items_Count++;
            return;
            break;
        }
    }
}

void CreateMagic(Enemy &self)
{
    for (int i = 0; i < MagicMax; i++)
    {
        if (MagicList[i].liv is false)
        {
            MagicList[i].liv = true;
            MagicList[i].x = self.base.x;
            MagicList[i].y = self.base.y + PlaneWeight + 10;
            MagicList[i].dtype = WeightChoice(MagicSelectWeight, 2);
            switch (MagicList[i].dtype)
            {
            case MT_FIRE:
            {
                MagicList[i].col = RGB(255, 255, 0);
            }
                break;
            
            case MT_BLIND:
            {
                MagicList[i].col = RGB(255, 255, 255);
            } break;
            
            default:
                break;
            }
            Magic_Count++;
            return;
        }
    }
    
}
void __Summon_DesignatedEnemy(int8_t Type_, int _x, int _y, DIRECT _d = -1)
{
    if (EnemyTypeWeight[1] > BossRateForWinner)
    {
        // reduce enemy summon. 1.7.10
        if (prob(60))
        {
            return;
        }
    }
    static int _[3] = {10, 10, 4};
    for (int i = 0; i < EnemyMax; i++)
    {
        if (EnemyList[i].liv == false)
        {
            EnemyList[i].liv = true;
            if (_d < 0 or _d > D_DOWN)
                EnemyList[i].d = WeightChoice(_, 3);
            else
                EnemyList[i].d = _d;
            EnemyList[i].dtype = Type_;
            EnemyList[i].base.y = _y;
            EnemyList[i].base.x = _x;
            EnemyList[i].base.hp= 1000;
            EnemyList[i].regen_thistick = 0;
            switch (EnemyList[i].dtype)
            {
            case ET_NORMAL:
            {
                EnemyList[i].base.color = RGB(255, 255, 8);
            }
                break;
            case ET_BOSS:
            {
                EnemyList[i].base.color = RGB(0xb3, 0x0e, 0xdc);
            } break;
            
            case ET_BOMB:
            {
                EnemyList[i].base.color = RGB(255, 32, 0);
                EnemyList[i].addon = -10;
            } break;
            
            case ET_MEDIC:
            {
                EnemyList[i].base.color = RGB(0, 255, 132);
                if (EnemyList[i].d is D_DOWN)
                {
                    // stand, and higher health
                    EnemyList[i].addon = 16;
                } else {
                    EnemyList[i].addon = 6;
                }
            }
            default:
                //errflg = true;
                //cerr(L"Error in summon enemy: Unknown dtype.");
                break;
            }
            Enemy_Count++;
            return;
            break;
        }
    }
    
}

void SummonCarrier()
{
    static int _[2] = {10, 10};
    for (int i = 0; i < EnemyMax; i++)
    {
        if (EnemyList[i].liv == false)
        {
            EnemyList[i].liv = true;
            EnemyList[i].d = WeightChoice(_, 2);
            EnemyList[i].dtype = ET_CARRIER;
            EnemyList[i].base.y = PlaneWeight+1;
            EnemyList[i].base.x = seg::Math::randint(PlaneWeight, Width - PlaneWeight);
            EnemyList[i].base.hp= CarrierHPMax;
            EnemyList[i].base.color = RGB(0,132,132);
            Enemy_Count++;
            CarrierBossBarMain = &(EnemyList[i]);
            __Summon_DesignatedEnemy(ET_MEDIC, EnemyList[i].base.x, EnemyList[i].base.y, seg::Math::randint(0,1));
            return;
            break;
        }
    }
}

void mov(Player &self)
{
    if (self.atkcool > 0)
    {
        self.atkcool --;
    }
    if (seg::Key::GetVirtualKey('A'))
    {
        self.base.x -= PlayerSpeed;
    } if (seg::Key::GetVirtualKey('D'))
    {
        self.base.x += PlayerSpeed;
    }
    if (seg::Key::GetVirtualKey('J') and self.atkcool <= 0)
    {
        shoot(self);
    }
    if (self.friend_tick > 0)
    {
        self.friend_tick --;
    }
    else 
    {
        if (seg::Key::GetVirtualKey('Q'))
        {
            SummonFriend(self, 1);
        }
        else if (seg::Key::GetVirtualKey('W'))
        {
            SummonFriend(self, 2);
        }
        else if (seg::Key::GetVirtualKey('E'))
        {
            constexpr double fulldeb = 180;
            const double _p = (PlayerShieldHpMax - self.ShieldHP) / PlayerShieldHpMax;
            const int needdeb = mid<decltype(needdeb)>(fulldeb * _p, 10, fulldeb);
            if (self.plane_debris >= needdeb)
            {
                self.plane_debris -= needdeb;
                self.ShieldHP = PlayerShieldHpMax;
            }
        }
    }
    if (pl.base.x < 0)
    {
        pl.base.x = 0;
    } else if (pl.base.x >= Width)
    {
        pl.base.x = Width;
    }
    // getitem
    if (self.Aid > 0)
    {
        self.Aid--;
        if (prob(82))
        {
            self.base.hp += 1;
            if (self.base.hp > 1000)
            {
                self.base.hp = 1000.0f;
            }
        }
    }
    if (self.Multishot > 0)
    {
        self.Multishot--;
    }
    if (self.Fire > 0)
    {
        self.Fire--;
        fire(self);
    }
    if (self.Blind > 0)
    {
        self.Blind --;
    }
    for (int i = 0; i < ItemMax; i++)
    {
        if (ItemList[i].liv)
        {
            if (EulaDis(self.base.x, self.base.y, ItemList[i].x, ItemList[i].y) < (PlaneWeight+ItemWeight))
            {
                ItemList[i].liv = false;
                Items_Count--;
                switch (ItemList[i].dtype)
                {
                case IT_POWER:
                {
                    self.Multishot = PowerTickMax;
                }
                    break;
                
                case IT_AID:
                {
                    self.Aid = AidTickMax;
                } break;
                
                case IT_SHIELD:
                {
                    self.ShieldHP = PlayerShieldHpMax;
                } break;
                
                default:
                    break;
                }
            }
        }
    }
    
}

void __mov_EnemyBomb(Enemy &self)
{
    if (self.addon > 0)
    {
        // had blast
        self.addon --;
        if (shadow_option.use  and  !shadow_option.spacecraft) {
            Shadow.light(self.base.x, self.base.y, self.addon);
        }
    }
    else if (self.addon > -9)
    {
        // clean
        self.liv = false;
        Enemy_Count--;
    }
    else
    {
        // await
        self.base.y += EnemySpeed;
        if (self.base.y >= Height)
        {
            self.liv = false;
            Enemy_Count--;
        }
        else
        {
            float dis = EulaDis(self.base.x, self.base.y, pl.base.x, pl.base.y);
            if (dis < EnemyBombBlastRange)
            {
                // bbb
                self.addon = (ADDON)get_tps(1600, 20);
                hit(pl, EnemyBombBlastDamageBase);
            }
        }
    }
}

void __mov_EnemyCarrier(Enemy &self)
{
    if (self.atkcool > 0)
    {
        self.atkcool --;
    }
    else
    {
        CreateMagic(self);
        self.atkcool = CarrierAtkcoolMax;
    }
    if (prob(CarrierRegeneratePer))
    {
        if (self.base.hp < CarrierHPMax)
        {
            self.base.hp += 1;
        }
    }
    if (prob(CarrierTrySummonEnemyPer))
    {
        if (prob(70))
        {
            __Summon_DesignatedEnemy(ET_BOMB, self.base.x, self.base.y, D_DOWN);
        } else {
            __Summon_DesignatedEnemy(ET_BOSS, self.base.x, self.base.y, D_DOWN);
        }
    }
    switch (self.d)
    {
    case D_LEFT:
    {
        self.base.x -= EnemySpeed;
        if (self.base.x < PlaneWeight)
        {
            if (true)
            {
                self.d = D_RIGHT;
                self.base.x += 2;
            }
        }
        else if (self.base.x < 0)
        {
            self.liv = false;
            Enemy_Count--;
        }
    }
        break;
    
    case D_RIGHT:
    {
        self.base.x += EnemySpeed;
        if (self.base.x > (Width - PlaneWeight))
        {
            if (true)
            {
                self.d = D_LEFT;
                self.base.x -= 2;
            }
        }
        else if (self.base.x >= Width)
        {
            self.liv = false;
            Enemy_Count--;
        }
    } break;
    
    case D_DOWN:
    {
        pass
    } break;
    
    default:
        break;
    }
}
void __mov_EnemyMedic(Enemy &self)
{
    for (int i = 0; i < EnemyMax; i++)
    {
        if (EnemyList[i].liv)
        {
            if (EulaDis(self.base.x, self.base.y, EnemyList[i].base.x, EnemyList[i].base.y)<(PlaneWeight*2+8))
            {
                if (true)
                {
                    //EnemyList[i].base.hp += self.addon;
                    EnemyList[i].regen_thistick += self.addon;
                }
                if (prob(50) and (EnemyList[i].dtype is ET_CARRIER))
                {
                    //EnemyList[i].base.hp += 5;
                    EnemyList[i].regen_thistick += 5;
                }
                /*
                if (EnemyList[i].dtype is ET_CARRIER)
                {
                    if (EnemyList[i].base.hp > CarrierHPMax)
                    {
                        EnemyList[i].base.hp = CarrierHPMax;
                    }
                }
                elif (EnemyList[i].base.hp > 1000)
                {
                    EnemyList[i].base.hp = 1000;
                }
                */
            }
        }
    }
    
    switch (self.d)
    {
    case D_LEFT:
    {
        self.base.x -= EnemySpeed;
        if (self.base.x < PlaneWeight)
        {
            if (true)
            {
                self.d = D_RIGHT;
                self.base.x += 2;
            }
        }
        else if (self.base.x < 0)
        {
            self.liv = false;
            Enemy_Count--;
        }
    }
        break;
    
    case D_RIGHT:
    {
        self.base.x += EnemySpeed;
        if (self.base.x > (Width - PlaneWeight))
        {
            if (true)
            {
                self.d = D_LEFT;
                self.base.x -= 2;
            }
        }
        else if (self.base.x >= Width)
        {
            self.liv = false;
            Enemy_Count--;
        }
    } break;
    
    case D_DOWN:
    {
        pass
    } break;
    
    default:
        break;
    }
}
void mov(Friend &self)
{
    if (shadow_option.use  and  shadow_option.spacecraft) {
        Shadow.light(self.base.x, self.base.y);
    }
    if (self.atkcool > 0)
    {
        self.atkcool --;
    }
    else
    {
        CreateBullet(self);
        switch (self.dtype)
        {
        case 2: {
            self.atkcool = get_tps(143);
        }
            break;
        
        case 1:
        default:
            self.atkcool = get_tps(860);
            break;
        }
    }
    switch (self.d)
    {
    case D_LEFT:
    {
        self.base.x -= EnemySpeed;
        if (self.base.x < PlaneWeight)
        {
            if (true)
            {
                self.d = D_RIGHT;
                self.base.x += 2;
            }
        }
        else if (self.base.x < 0)
        {
            self.liv = false;
        }
    }
        break;
    
    case D_RIGHT:
    {
        self.base.x += EnemySpeed;
        if (self.base.x > (Width - PlaneWeight))
        {
            if (true)
            {
                self.d = D_LEFT;
                self.base.x -= 2;
            }
        }
        else if (self.base.x >= Width)
        {
            self.liv = false;
        }
    } break;
    
    case D_DOWN:
    {
        self.base.y -= EnemySpeed * 0.9;
        if (self.base.y <= 0)
        {
            self.liv = false;
        }
    } break;
    
    default:
        break;
    }
}
void mov(Enemy & self)
{
    if (shadow_option.use  and  shadow_option.spacecraft) {
        Shadow.light(self.base.x, self.base.y);
    }
    if (self.regen_thistick > EnemyRegenerationMaxInOneTickTime)
    {
        self.regen_thistick = EnemyRegenerationMaxInOneTickTime;
    }
    self.base.hp += self.regen_thistick;
    self.regen_thistick = 0;
    if (self.dtype is ET_CARRIER)
    {
        if (self.base.hp > CarrierHPMax)
        {
            self.base.hp = CarrierHPMax;
        }
    }
    elif (self.base.hp > 1000)
    {
        self.base.hp = 1000;
    }
    if (self.dtype is ET_BOMB)
    {
        __mov_EnemyBomb(self);
        return;
    }
    elif (self.dtype  is  ET_CARRIER)
    {
        __mov_EnemyCarrier(self);
        return;
    }
    elif (self.dtype  is  ET_MEDIC)
    {
        __mov_EnemyMedic(self);
        return;
    }
    if (self.atkcool > 0)
    {
        self.atkcool --;
    }
    else
    {
        shoot(self);
    }
    switch (self.d)
    {
    case D_LEFT:
    {
        self.base.x -= EnemySpeed;
        if (self.base.x < PlaneWeight)
        {
            if (prob(EnemyNotEscapeProb))
            {
                self.d = D_RIGHT;
                self.base.x += 2;
            }
        }
        else if (self.base.x < 0)
        {
            self.liv = false;
            Enemy_Count--;
        }
    }
        break;
    
    case D_RIGHT:
    {
        self.base.x += EnemySpeed;
        if (self.base.x > (Width - PlaneWeight))
        {
            if (prob(EnemyNotEscapeProb))
            {
                self.d = D_LEFT;
                self.base.x -= 2;
            }
        }
        else if (self.base.x >= Width)
        {
            self.liv = false;
            Enemy_Count--;
        }
    } break;
    
    case D_DOWN:
    {
        self.base.y += EnemySpeed;
        if (self.base.y >= Height)
        {
            self.liv = false;
            Enemy_Count--;
        }
    } break;
    
    default:
        break;
    }
}

void mov(Bullet &self)
{
    self.x += self.dx;
    self.y += self.dy;
    if (shadow_option.use  and  shadow_option.bullet) {
        Shadow.light(self.x, self.y, shadow_option.bullet);
    }
    if (true) // (self.belong is EB_PLAYER)
    {
        for (int i = 0; i < EnemyMax; i++)
        {
            if (EnemyList[i].liv == true)
            {
                if (EulaDis(self.x, self.y, EnemyList[i].base.x, EnemyList[i].base.y) < (PlaneWeight + BulletWeight))
                {
                    hit(EnemyList[i], self.damage, self.belong);
                    self.liv = false;
                    BulletCount--;
                    if (self.belong is EB_PLAYER)
                    {
                        StatisticalData.onTarget++;
                    }
                    return;
                }
            }
        }
        for (int i = 0; i < FriendMax; i++)
        {
            if (FriendList[i].liv == true)
            {
                if (EulaDis(self.x, self.y, FriendList[i].base.x, FriendList[i].base.y) < (PlaneWeight + BulletWeight))
                {
                    float dmg0 = self.damage;
                    if (self.belong == EB_PLAYER) {
                        dmg0 = self.damage * 0.2;
                    }
                    hit(FriendList[i], dmg0, self.belong);
                    self.liv = false;
                    BulletCount--;
                    return;
                }
            }
        }
        if (EulaDis(self.x, self.y, pl.base.x, pl.base.y) < (PlaneWeight + BulletWeight))
        {
            if (self.belong != EB_PLAYER)
            {
                hit(pl, self.damage);
                self.liv = false;
                BulletCount--;
                return;
            }
        }
    }
    if (self.x >= Width or self.x < 0 or self.y >= Height or self.y < 0)
    {
        self.liv = false;
        BulletCount--;
        return;
    }
}

void mov(Meteorite &self)
{
    switch (self.movem)
    {
    case MM_YLINE:
    {
        self.y += self.yspeed;
    }
        break;
    
    case MM_FLOAT:
    {
        self.y += self.yspeed;
        self.x += self.xspeed;
        if (prob(30))
        {
            self.xspeed += windy;
        }
    }
    default:
        break;
    }
    
    if (self.x < 0 or self.x >= Width or self.y < 0 or self.y >= Height)
    {
        self.liv = false;
        Stone_Count--;
        return;
    }
    if (EulaDis(self.x, self.y, pl.base.x, pl.base.y) < (PlaneWeight + self.radius))
    {
        hit(pl, MeteoriteDamageBase);
    }
    for (int i = 0; i < EnemyMax; i++)
    {
        if (EnemyList[i].liv is true)
        {
            if (EulaDis(self.x, self.y, EnemyList[i].base.x, EnemyList[i].base.y) < (PlaneWeight + self.radius))
            {
                hit(EnemyList[i], MeteoriteDamageBase, -1);
            }
        }
    }
    for (int i = 0; i < FriendMax; i++)
    {
        if (FriendList[i].liv is true)
        {
            if (EulaDis(self.x, self.y, FriendList[i].base.x, FriendList[i].base.y) < (PlaneWeight + self.radius))
            {
                hit(FriendList[i], MeteoriteDamageBase, -1);
            }
        }
    }
    if (CanMeteoriteDestroyBullet is true)
    {
        for (int i = 0; i < BulletMax; i++)
        {
            if (BulletList[i].liv is true)
            {
                if (EulaDis(self.x, self.y, BulletList[i].x, BulletList[i].y) < (BulletWeight + self.radius))
                {
                    BulletList[i].liv = false;
                    BulletCount--;
                }
            }
        }
        
    }
}


void mov(Item &self)
{
    self.y += ItemSpeed;
    if (self.y >= Height)
    {
        self.liv = false;
        Items_Count--;
    }
}

void mov(Magic &self)
{
    self.y += MagicSpeed;
    if (prob(87))
    {
        self.x += windy;
    }
    if (self.y >= Height  or self.x < 0  or self.x >= Width)
    {
        self.liv = false;
        Magic_Count--;
        return;
    }
    if (EulaDis(self.x, self.y, pl.base.x, pl.base.y) < (PlaneWeight + MagicWeight))
    {
        switch (self.dtype)
        {
            case MT_FIRE:
            {
                pl.Fire = FireTickMax;
            } break;
            
            case MT_BLIND:
            {
                pl.Blind = BlindTickMax;
            } break;
            
            default:
            {
                break;
            }
        }
        self.liv = false;
        Magic_Count--;
        return;
    }
}

void shoot(Player &self)
{
    CreateBullet(self);
    self.atkcool = PlayerAtkCool;
    StatisticalData.Shoot++;
}

void shoot(Enemy &self)
{
    CreateBullet(self);
    self.atkcool = EnemyAtkCool;
}

void hit(Player &self, float dmg0)
{
    float dmg = dmg0;
    if (self.ShieldHP > 0)
    {
        dmg = dmg * (1 - self.ShieldHP / PlayerShieldHpMax) * ShieldReduceDamagePer;
        if (dmg < 0) dmg = 0.0001;
        self.ShieldHP -= (dmg <= 15 ? 15 : (float)(dmg >= 50 ? 50 : dmg));
        if (self.ShieldHP < 0)
        {
            self.ShieldHP = 0;
        }
        StatisticalData.ShieldAbsorb += (dmg0 - dmg);
    }
    self.base.hp -= dmg;
    if (self.base.hp < 0)
    {
        self.base.hp = 0;
    }
    StatisticalData.behit += dmg;
}

void hit(Enemy &self, float dmg, int8_t by)
{
    self.base.hp -= dmg;
    if (self.base.hp <= 0)
    {
        self.liv = false;
        Enemy_Count--;
        if (by is EB_PLAYER)
        {
            StatisticalData.q++;
            switch (self.dtype)
            {
            case ET_NORMAL:
            {
                score++;
                StatisticalData.q_normal ++;
                pl.plane_debris += RandomDistInt(0, 2);
            }
                break;
            case ET_BOSS:
            {
                score += 2;
                StatisticalData.q_boss ++;
                pl.plane_debris += RandomDistInt(1, 3);
            } break;
            
            case ET_BOMB:
            {
                score += 4;
                StatisticalData.q_bomb ++;
                pl.plane_debris += RandomDistInt(1, 4);
            } break;
            
            case ET_CARRIER:
            {
                score += 8;
                StatisticalData.q_carrier ++;
                pl.plane_debris += RandomDistInt(5, 16);
            } break;
            
            case ET_MEDIC:
            {
                score += 5;
                StatisticalData.q_medic++;
                pl.plane_debris += RandomDistInt(1, 2);
            }
            default:
                break;
            }
            StatisticalData.hit += dmg;
        }
        if (
            //((self.dtype is ET_BOSS) or (self.dtype is ET_CARRIER) or (self.dtype is ET_BOMB)) and
            // 1.7.10 change to.
            prob(GetItemPer) and self.dtype != ET_NORMAL
        )
        {
            CreateItem(self);
        }
        elif (prob((100 - GetItemPer) / 8 + 2) )
        {
            CreateItem(self);
        }
    }
}
void hit(Friend &self, float dmg, int8_t by)
{
    self.base.hp -= dmg;
    if (self.base.hp <= 0)
    {
        self.liv = false;
    }
}

void fire(Player &self)
{
    self.base.hp -= 4;
    if (self.ShieldHP > 0)
    {
        self.ShieldHP --;
    }
}

void __render_PlayerHud(Player &self)
{
    float per = self.base.hp / 1000.00f;
    constexpr int llen = 700;
    rectangle(100, 900, 100+llen, 910);
    if (self.Aid > 0)
    {
        setfillcolor(RGB(96, 255, 8));
    }else{
        setfillcolor(RGB(254, 37, 70));
    }
    fillrectangle(101, 901, 101+((llen-2) * per), 909);
    per = self.ShieldHP / PlayerShieldHpMax;
    rectangle(100 + 100 + llen , 900, 100 + llen + 100+llen, 910);
    setfillcolor(RGB(235, 198, 20));
    fillrectangle(201 + llen, 901, 202 + llen +((llen-1) * per), 909);
    TCHAR buf[12];
    settextcolor(RGB(196, 234, 30));
    swprintf_s(buf, 12, L"%d", self.plane_debris);
    outtextxy(1, 920-12, buf);
    settextcolor(RGB(255, 160, 255));
}
void render(Player &self)
{
    if (self.Fire > 0)
        setlinecolor(RGB(255, 186, 8));
    else
        setlinecolor(self.base.color);
    circle(self.base.x, self.base.y, PlaneWeight);
    line(self.base.x - PlaneWeight, self.base.y, self.base.x + PlaneWeight, self.base.y);
    line(self.base.x - PlaneWeight, self.base.y, self.base.x, self.base.y - (PlaneWeight/5));
    line(self.base.x, self.base.y - (PlaneWeight/5), self.base.x + PlaneWeight, self.base.y);
    __render_PlayerHud(self);
}

void render(Enemy &self)
{
    setlinecolor(self.base.color);
    if ((self.dtype is ET_BOMB) and (self.addon > 0))
    {
        setfillcolor(self.base.color);
        fillcircle(self.base.x, self.base.y, PlaneWeight);
        return;
    }
    circle(self.base.x, self.base.y, PlaneWeight);
    line(self.base.x - PlaneWeight, self.base.y, self.base.x + PlaneWeight, self.base.y);
    line(self.base.x - PlaneWeight, self.base.y, self.base.x, self.base.y + (PlaneWeight/5));
    line(self.base.x, self.base.y + (PlaneWeight/5), self.base.x + PlaneWeight, self.base.y);
}
void render(Friend &self)
{
    setlinecolor(self.base.color);
    circle(self.base.x, self.base.y, PlaneWeight);
    line(self.base.x - PlaneWeight, self.base.y, self.base.x + PlaneWeight, self.base.y);
    line(self.base.x - PlaneWeight, self.base.y, self.base.x, self.base.y + (PlaneWeight/5));
    line(self.base.x, self.base.y + (PlaneWeight/5), self.base.x + PlaneWeight, self.base.y);
}

void render(Bullet &self)
{
    setlinecolor(self.col);
    setfillcolor(self.col);
    fillcircle(self.x, self.y, BulletWeight);
}

void render(Meteorite &self)
{
    setlinecolor(RGB(170, 85, 0));
    setfillcolor(RGB(170, 85, 0));
    fillcircle(self.x, self.y, self.radius);
}

void render(Item &self)
{
    switch (self.dtype)
    {
    case IT_POWER:
    {
        setlinecolor(RGB(57, 11, 244));
        circle(self.x, self.y, ItemWeight);
        line(self.x, self.y + int(ItemWeight * 0.6667), self.x - 3, self.y - 3);
        line(self.x, self.y + int(ItemWeight * 0.6667), self.x + 3, self.y + 3);
        line(self.x, self.y + int(ItemWeight * 0.6667), self.x , self.y - 6);
    }
        break;
    
    case IT_AID:
    {
        setlinecolor(RGB(0, 255, 8));
        setfillcolor(RGB(0, 255, 8));
        circle(self.x, self.y, ItemWeight);
        fillrectangle(
            self.x - int(ItemWeight*0.67), self.y - int(ItemWeight*0.33), 
            self.x + int(ItemWeight*0.67), self.y + int(ItemWeight*0.33)
        );
        fillrectangle(
            self.x - int(ItemWeight*0.33), self.y - int(ItemWeight*0.67), 
            self.x + int(ItemWeight*0.33), self.y + int(ItemWeight*0.67)
        );
    } break;
    
    case IT_SHIELD:
    {
        setlinecolor(RGB(235 ,198, 20));
        setfillcolor(RGB(235, 198, 20));
        circle(self.x, self.y, ItemWeight);
        fillrectangle(
            self.x - int(ItemWeight*0.33), self.y - int(ItemWeight*0.67), 
            self.x + int(ItemWeight*0.33), self.y + int(ItemWeight*0.67)
        );
    }
    default:
        break;
    }
}

void render(Magic &self)
{
    setlinecolor(self.col);
    setfillcolor(self.col);
    fillcircle(self.x, self.y, MagicWeight);
}


void draw_bar(Enemy *carrier)
{
    if (carrier is nullptr)
    {
        return;
    }
    elif (carrier->dtype != ET_CARRIER)
    {
        return;
    }
    else if (carrier->base.hp > 0)
    {
        const float per = carrier->base.hp / CarrierHPMax;
        constexpr int wlen = Width - 400 - 400;
        // 400->(wlen)->400
        const int barlen = wlen * per;
        setlinecolor(RGB(0, 120, 120));
        setfillcolor(RGB(0, 120, 120));
        fillrectangle(400, 20, 400+wlen+2, 40);
        setlinecolor(RGB(255, 128, 128));
        setfillcolor(RGB(255, 128, 128));
        fillrectangle(401, 21, 400 + barlen, 38);
        seg::render::text(Width/2, 10, L"Boss Carrier", seg::render::Place::center);
    }
}

void Introduce()
{
    constexpr COLORREF bullet_1 = RGB(255, 0, 255);
    constexpr COLORREF bullet_2 = RGB(0xc5, 0xfb, 0x46);
    constexpr COLORREF bullet_3 = RGB(0xc5, 0xfb, 0x66);
    constexpr COLORREF enemy_normal = RGB(255,255,8);
    constexpr COLORREF enemy_boss = RGB(0xb3, 0x0e, 0xdc);
    constexpr COLORREF enemy_bomb = RGB(255,32,0);
    constexpr COLORREF enemy_carrier = RGB(0, 132, 132);
    const COLORREF enemycolor[4]{enemy_normal, enemy_boss, enemy_bomb, enemy_carrier};
    const wchar_t* enemyDesc[4] = {
        L"普通类型", L"高级类型, 注意避开它射击的粉色子弹",
        L"炸弹小飞机, 靠近玩家时会爆炸, 伤害高",
        L"游戏Boss, 能射出魔法子弹并给玩家debuff(燃烧、失明),会召唤其他敌对势力"
    };
    Bullet b1{100, 80, 1, 0, 0, true, EB_ENEMY, bullet_1};
    Bullet b2{200, 80, 1, 0, 0, true, EB_ENEMY, bullet_2};
    Bullet b3{300, 80, 1, 0, 0, true, EB_ENEMY, bullet_3};
    Enemy EE[4];
    for (int i = 0; i < 4; i++)
    {
        EE[i].base.x = i * PlaneWeight * 10 + 100;
        EE[i].base.y = 180;
        EE[i].base.color = enemycolor[i];
    }
    Meteorite st;
    st.x = 180;
    st.y = 400;
    st.radius = 100;
    Enemy medical;
    medical.dtype = ET_MEDIC;
    medical.base.x = 520;
    medical.base.y = 400;
    medical.base.color = RGB(0, 255, 132);
    Item its[3];
    for (int i = 0; i < 3; i++)
    {
        its[i].x = i * ItemWeight * 50 + 120;
        its[i].y = 560;
    }
    its[0].dtype = IT_POWER;
    its[1].dtype = IT_AID;
    its[2].dtype = IT_SHIELD;
    const wchar_t* itemDesc[3] = {
        L"力量效果, 让玩家可以多重射击", L"再生药水, 加快生命值的回复", L"抗性提升, 抵消部分受到的伤害"
    };
    while (true)
    {
        Sleep(60);
        seg::render::fill(RGB(60, 60, 80));
        render(b1); render(b2); render(b3);
        outtextxy(100, 100, L"各种子弹。粉红色的子弹伤害高, 避免被它们射中! ");
        for (int i = 0; i < 4; i++)
        {
            render(EE[i]);
            seg::render::text(EE[i].base.x, EE[i].base.y+80, (TCHAR*)enemyDesc[i], seg::render::Place::center);
        }
        render(st);
        outtextxy(50, 520, L"陨石, 可对所有实体造成伤害(不包括item、magic)");
        render(medical);
        seg::render::text(medical.base.x, 520, L"治疗敌方, 由Carrier召唤", seg::render::Place::center);
        for (int i = 0; i < 3; i++)
        {
            render(its[i]);
            seg::render::text(its[i].x, its[i].y + 40, (TCHAR*)itemDesc[i], seg::render::Place::center);
        }
        outtextxy(100, 630, L"WASD移动, J射击, P暂停; 左下角为飞船碎片数量, 可用于制造/修复飞船, Q/W召唤友军, E修复护盾");
        outtextxy(100, 660, L"按ESC退出");
        seg::render::flip();
        if (seg::Key::GetVirtualKey(VK_ESCAPE))
        {
            return;
        }
    }
}

void ShowStatistics()
{
    constexpr int xx = 100;
    constexpr int yadd = 50;
    constexpr COLORREF bg = RGB(32, 63+1, 96);
    wchar_t s[100];
    int y;
    while (true)
    {
        Sleep(60);
        seg::render::fill(bg);
        y = 50;
        swprintf(s, L"%30s    %hd(win: %hd, lose: %hd)", L"游玩次数", StatisticalData.PlayTimes,StatisticalData.passTimes, StatisticalData.losetimes);
        outtextxy(xx, y, s);
        y += yadd;
        swprintf(s, L"%30s    %ld", L"射击次数", StatisticalData.Shoot);
        outtextxy(xx, y, s);
        y += yadd;
        swprintf(s, L"%30s    %ld", L"击中次数", StatisticalData.onTarget);
        outtextxy(xx, y, s);
        y += yadd;
        swprintf(s, L"%30s    %d(%d,%d,%d,%d,%d)", L"击杀次数", StatisticalData.q, StatisticalData.q_normal, StatisticalData.q_boss, StatisticalData.q_bomb, StatisticalData.q_carrier, StatisticalData.q_medic);
        outtextxy(xx, y, s);
        y += yadd;
        swprintf(s, L"%30s    %ld", L"得分", StatisticalData.score);
        outtextxy(xx, y, s);
        y += yadd;
        swprintf(s, L"%30s    %lf", L"受到伤害", StatisticalData.behit);
        outtextxy(xx, y, s);
        y += yadd;
        swprintf(s, L"%30s    %lf", L"造成伤害", StatisticalData.hit);
        outtextxy(xx, y, s);
        y += yadd;
        swprintf(s, L"%30s    %lf", L"吸收伤害", StatisticalData.ShieldAbsorb);
        outtextxy(xx, y, s);
        y += yadd;
        seg::render::flip();
        if (seg::Key::GetVirtualKey(VK_ESCAPE))
        {
            break;
        }
    }
    
}

void _Shadow::light(int x, int y, int l, int dec)
{
    if (l <= 0) {
        return;
    }
    elif (l == 1) {
        increase255(this->lightmap[y][x].r, 1);
        increase255(this->lightmap[y][x].g, 1);
        increase255(this->lightmap[y][x].b, 1);
        return;
    }
    else {
        if (l > 255) {
            l = 255;
        }
        int xx, yy;
        xx = x ;
        yy = y;
        while (l > 0) {
            xx--;
            while (xx < x){
                if (0 <= xx && xx < Width && 0 <= yy && yy < Height){
                    increase255(this->lightmap[yy][xx].r, l);
                    increase255(this->lightmap[yy][xx].g, l);
                    increase255(this->lightmap[yy][xx].b, l);
                }
                xx++;
                yy--;
            }
            while (yy < y){
                if (0 <= xx && xx < Width && 0 <= yy && yy < Height){
                    increase255(this->lightmap[yy][xx].r, l);
                    increase255(this->lightmap[yy][xx].g, l);
                    increase255(this->lightmap[yy][xx].b, l);
                }
                xx++;
                yy++;
            }
            while (xx > x){
                if (0 <= xx && xx < Width && 0 <= yy && yy < Height){
                    increase255(this->lightmap[yy][xx].r, l);
                    increase255(this->lightmap[yy][xx].g, l);
                    increase255(this->lightmap[yy][xx].b, l);
                }
                xx--;
                yy++;
            }
            while (yy > y){
                if (0 <= xx && xx < Width && 0 <= yy && yy < Height){
                    increase255(this->lightmap[yy][xx].r, l);
                    increase255(this->lightmap[yy][xx].g, l);
                    increase255(this->lightmap[yy][xx].b, l);
                }
                xx--;
                yy--;
            }
            l -= dec;
        }
    }
}

struct __bl_datas
{
    bool a[4];
    int k;
}bl_datas;

void _Shadow::bl(int start)
{
    static int st = start;
}

void __blit__light_(_Shadow *self, int h, int h2)
{
    DWORD *p = GetImageBuffer();
    for (int i = h; i <= h2; i++)
    {
        for (int j = 0; j < Width; j++)
        {
            p[i * Width + j] = RGB(self->lightmap[i][j].r, self->lightmap[i][j].g, self->lightmap[i][j].b);
        }
    }
    bl_datas.k ++;
}

void _Shadow::blit_light()
{
    DWORD *p = GetImageBuffer();
    
    #pragma omp parallel for num_threads(4)
    for (int i = 0; i < Height; i++)
    {
        for (int j = 0; j < Width; j++)
        {
            p[i * Width + j] = RGB(this->lightmap[i][j].r, this->lightmap[i][j].g, this->lightmap[i][j].b);
        }
    }
    
    /*
    bl_datas.k = 0;
    std::thread(__blit__light_, this, 0, 310).detach();
    std::thread(__blit__light_, this, 311, 625).detach();
    std::thread(__blit__light_, this, 625, Height-1).detach();
    while (bl_datas.k < 3){
        ;
    }
    */
    //putimage(0,0,&this->bg);
}

// null comment
void Stars_::mov_and_render()
{
    if (prob(3)) {
        this->y ++;
    }
    if (this->xmovtick > 0) {
        this->xmovtick--;
    } else {
        this->x += windy;
        this->xmovtick = 26;
    }
    if (this->displaying) {
        
        if (prob(5-1)) {
            this->big = ! this->big;
        }
        
        //new?
        /*
        if (prob(4)) {
            if (prob(40)) {
                this->big = true;
            }
        }*/
        //putpixel(this->x, this->y, this->col);
        if (this->big){
                setfillcolor(this->col);
                solidcircle(this->x, this->y, 1);
            }
        else
            putpixel(this->x, this->y, this->col);
    }
    if (options.twinkling_stars) {
        long long tim = seg::Times::get_ticks();
        if (tim > this->display) {
            this->display = tim + RandomDistInt(100, 1862);
            this->displaying = ! this->displaying;
        }
    }
    if (this->x > 0 && this->x < Width  &&  this->y > 0 && this->y < Height) {
        if (prob(2)) {
            if (prob(2)) {
                if (prob(8)) {
                    this->init();
                }
            }
        }
    } else {
        this->init();
    }
}

namespace StarmapNs {
    int startype;
    bool showbigstars;
    std::array<Stars_, 5260> randommap;
    class Bigstar{
        public:
            int x;
            int y;
            int r;
            COLORREF col;
            tick_t xmov;
            void init(){
                this->x = RandInt(48, Width-56);
                this->y = prob(90-10)? RandInt(Height * 0.3, Height * 0.7) : RandInt(0, Height);
                this->r = RandInt(1,4);
                this->col = RGB(RandInt(220,254), RandInt(168,254), RandInt(136,254));
                this->xmov = 60;
                this->x += ((Width / 2  -  this->x) * RandInt(0, 50) / 100);
                this->y += ((Height/2 - this->y) * (abs(Width/2 - this->x) / (Width / 2)));
            }
            void move() {
                setfillcolor(this->col);
                solidcircle(this->x, this->y, this->r);
                if (this->xmov <= 0) {
                    this->xmov = 68;
                    this->x += windy;
                    if (this->x < 0 or this->x >= Width or this->y < 0 or this->y >= Height) {
                        this->init();
                    }
                } else {
                    this->xmov -= 1;
                }
            }
    };
    std::array<Bigstar, 2080> bigstars;
    int Starmap_h(EasyCtrl* ecp, ExMessage *msg, int *p)
    {
        switch (*p)
        {
        case 0:{
            return true;
        }
            break;
        
        case 1:{
            StarmapNs::showbigstars = !StarmapNs::showbigstars;
        } break;
        
        default:
            break;
        }
        return false;
    }

    void Starmap_r()
    {
        if (StarmapNs::showbigstars) {
            Shadow.reset();
        }else{
            seg::render::fill(RGB(8,10,12));
        }
        
        if (StarmapNs::showbigstars) {
            for (int i = 0; i < StarmapNs::bigstars.size(); i++)
            {
                Shadow.light(StarmapNs::bigstars.at(i).x, StarmapNs::bigstars.at(i).y, 36);
            }
            Shadow.blit_light();
            FlushBatchDraw();
            #pragma omp parallel for num_threads(2)
            for (auto i = 0; i < StarmapNs::randommap.size(); i++) {
                StarmapNs::randommap.at(i).mov_and_render();
            }
            #pragma omp parallel for num_threads(2)
            for (int i = 0; i < StarmapNs::bigstars.size(); i++)
            {
                StarmapNs::bigstars.at(i).move();
            }
        } else {
            #pragma omp parallel for num_threads(2)
            for (auto i = 0; i < StarmapNs::randommap.size(); i++) {
                StarmapNs::randommap.at(i).mov_and_render();
            }
        }
        FlushBatchDraw();
        if (prob(4)) {
            if (prob(6)) {
                if (prob(48))
                {
                    windy = seg::Math::randint(0, 2);
                }
                else if (prob(92))
                {
                    windy = -seg::Math::randint(0, 2);
                } else {
                    windy = 0;
                }
            }
        }
    }
    void Starmap()
    {
        StarmapNs::startype = 0;
        StarmapNs::showbigstars = false;
        for (auto i = 0; i < StarmapNs::randommap.size(); i++) {
            StarmapNs::randommap.at(i).init();
        }
        for (auto i = 0; i < StarmapNs::bigstars.size(); i++) {
            StarmapNs::bigstars.at(i).init();
        }
        easygui eg(3, RandomColor(), Starmap_h);
        eg.pack_button(Width*0.96,Height-32,Width*0.039,30,_T("退出"),RandomColor(60,120),
            randcolor_lighter(), RandomColor(163,236),nullptr);
        eg.pack_button(Width*0.92, Height-32, Width*0.039 - 3, 30,_T("showbig"),RandomColor(60,120),
            randcolor_lighter(), RandomColor(163,238),nullptr);
        eg.wait(StarmapNs::Starmap_r, 0);
    }
}
int Options__::_main_h(EasyCtrl *ecp, ExMessage *msg, int *p)
{
    switch (*p)
    {
    case 0: {
        // sure
        return true;
    }
        break;
    
    case 1:{
        options.shader();
    } break;
    
    case 2:{
        options._display();
    }
    break;
    
    default:
    return false;
    break;
    }
    return false;
}
void Options__::_main()
{
    //shadow, key
    constexpr int BTNH = 48;
    easygui eg(3, RandomColor(65,128), this->_main_h);
    eg.pack_button(Width*0.19, 700, Width*0.62, BTNH, _T("确定"), RandomColor(),RandomColor(),
        RandomColor(),nullptr);
    eg.pack_button(Width*0.19, 200, Width*0.3, BTNH,_T("光影"),RandomColor(),RandomColor(),
        RandomColor(), nullptr);
    eg.pack_button(Width*0.51,200,Width*0.3,BTNH,_T("显示"),RandomColor(),
        RandomColor(),RandomColor(),nullptr);
    eg.mainloop();
}

int __options_shader_helper(EasyCtrl *ecp, ExMessage *msg, int *p)
{
    switch (*p)
    {
    case 1:
    {
        shadow_option.use = ecp->checker.isSelected;
        return 0;
    }
        break;
    case 2:
    {
        //shadow_option.bullet = ecp->checker.isSelected;
        if (ecp->checker.isSelected) {
            shadow_option.bullet = 48;
        } else {
            shadow_option.bullet = 0;
        }
        return 0;
    } break;
    
    case 3:{
        shadow_option.star = ecp->checker.isSelected;
        return 0;
    }
    case 4:
    {
        // sure
        return true;
    } break;
    
    default:
        return false;
        break;
    }
    return 0;
}

void Options__::shader()
{
    easygui eg(5, RandomColor(65,128), __options_shader_helper);
    eg.pack_text(Width*0.1, 50, Width*0.8, 60, _T("光影设置"), RandomColor(0, 128),RandomColor(180,254),
        RandomColor(180,254), nullptr);
    eg.pack_checker(50, 150, 260, 20, _T("启用光影"), RandomColor(180,254),RandomColor(180,254),
        shadow_option.use,nullptr);
    eg.pack_checker(50, 210, 260, 20, _T("闪光弹"),RandomColor(180,254),RandomColor(180,254),
        shadow_option.bullet, nullptr);
    eg.pack_checker(50, 270, 260, 20, _T("星空(exp)"), RandomColor(180, 254), RandomColor(168, 248), 
        shadow_option.star, nullptr);
    eg.pack_button(Width*0.3, Height-130, Width*0.4, 56, _T("确定"), RandomColor(0, 128),RandomColor(180,254),
        RandomColor(180,254), nullptr);
    eg.mainloop();
}

int Options__::_display_h(EasyCtrl *ecp, ExMessage *msg, int *p)
{
    switch (*p)
    {
    case 0: {
        return true;
    }
        break;
    
    case 1: {
        pass;
    } break;
    
    case 2: {
        options.display_star = ecp->checker.isSelected;
    } break;
    
    case 3:{
        options.random_star_color = ecp->checker.isSelected;
    } break;
    
    case 4: {
        options.twinkling_stars = ecp->checker.isSelected;
    } break;
    
    case 5:{
        StarmapNs::Starmap();
    } break;
    
    default:
        break;
    }
    return false;
}

void Options__::_display()
{
    easygui eg(6, RandomColor(65, 128), this->_display_h);
    eg.pack_button(Width*0.3, Height-130,Width*0.4, 56, _T("确定"), RandomColor(0,128),
        RandomColor(160,254), RandomColor(160,254), nullptr);
    eg.pack_text(Width*0.1,48,Width*0.8,60,_T("显示设置"),RandomColor(0,128),RandomColor(180,254),
        RandomColor(180,254),nullptr);
    eg.pack_checker(50, 150, 240, 20, _T("开启星空"), RandomColor(160,253),RandomColor(160,254),
        this->display_star, nullptr);
    eg.pack_checker(520, 150, 700, 20, _T("随机星星颜色"),RandomColor(160,254),RandomColor(160,254),
        this->random_star_color, nullptr);
    eg.pack_checker(920, 150, 0, 20, _T("闪烁的星星"), RandomColor(160,254),RandomColor(160,254),
        this->twinkling_stars, nullptr);
    eg.pack_button(1320, 142, 100, 36, _T("starmap"),RandomColor(0,128),
        RandomColor(160,236), RandomColor(160,236), nullptr);
    eg.mainloop();
}

#undef and
#undef is
#undef or
#undef elif